package dbutils

import (
	"errors"
	"strings"
	"time"

	"gitee.com/haodreams/golib/logs"
	"gorm.io/gorm"
)

// Time 时间自动格式化
type Time struct {
	time.Time
}

// MarshalJSON implements the json.Marshaler interface.
// The time is a quoted string in RFC 3339 format, with sub-second precision added if present.
func (t Time) MarshalJSON() ([]byte, error) {
	if y := t.Year(); y < 0 || y >= 10000 {
		// RFC 3339 is clear that years are 4 digits exactly.
		// See golang.org/issue/4556#c15 for more discussion.
		return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
	}

	b := make([]byte, 0, len("2006-01-02 15:04:05")+2)
	b = append(b, '"')
	b = t.AppendFormat(b, "2006-01-02 15:04:05")
	b = append(b, '"')
	return b, nil
}

// UnmarshalJSON implements the json.Unmarshaler interface.
// The time is expected to be a quoted string in RFC 3339 format.
func (t *Time) UnmarshalJSON(data []byte) error {
	// Ignore null, like in the main JSON package.
	if string(data) == "null" {
		return nil
	}
	// Fractional seconds are handled implicitly by Parse.
	var err error
	t.Time, err = time.Parse(`"2006-01-02 15:04:05"`, string(data))
	return err
}
func (t *Time) String() string {
	return t.Format("2006-01-02 15:04:05")
}

// AppConf 定义配置表结构
type AppConf struct {
	UpdatedAt Time
	ID        uint     `gorm:"primary_key"`
	Parent    string   `gorm:"type:varchar(255)"`
	Scope     string   `gorm:"type:varchar(255)"`           //测点类型, 是否是高级
	Name      string   `gorm:"type:varchar(255)"`           //页面显示的数据
	Key       string   `gorm:"type:varchar(255)"`           //显示数据对应的KEY
	Value     string   `gorm:"type:varchar(255)"`           //需要配置的值
	Desc      string   `gorm:"type:varchar(255);column:ed"` //描述信息
	Type      string   `gorm:"type:varchar(255)"`           //填充模式
	Data      string   `gorm:"type:varchar(255)"`           //字段候选值
	Rows      []string `gorm:"-"`                           //字段候选值,供前台使用
}

// Insert 新建
func (a *AppConf) Insert(db *gorm.DB) error {
	return db.Create(a).Error
}

// Update 更新
func (a *AppConf) Update(db *gorm.DB) error {
	var b AppConf
	err := db.First(&b, "key=? AND parent = ?", a.Key, a.Parent).Error
	if err == nil {
		a.ID = b.ID
	}
	return db.Save(a).Error
}

// Delete 删除
func (a *AppConf) Delete(db *gorm.DB) error {
	return db.Delete(a).Error
}

// DeleteByParent 删除指定的数据
func (a *AppConf) DeleteByParent(db *gorm.DB, parent string) error {
	return db.Where("parent=?", parent).Delete(&AppConf{}).Error
}

// Map ...
func Map(parent string) (m map[string]string, err error) {
	m = map[string]string{}
	if confdb == nil {
		err = errors.New("database is not set for config")
		return
	}
	var rows []*AppConf
	if parent != "" {
		rs := confdb.Where("parent = ?", parent).Find(&rows)
		if rs.Error != nil {
			err = rs.Error
			return
		}
	} else {
		rs := confdb.Find(&rows)
		if rs.Error != nil {
			err = rs.Error
			return
		}
		for _, row := range rows {
			m[row.Key] = row.Value
		}
	}
	return
}

// MakeDetails 生成行
func MakeDetails(parent string, prefix ...string) (rows []*AppConf, err error) {
	rows, err = Find(parent)
	if err != nil {
		return
	}
	for _, row := range rows {
		if row.Type == "select" {
			row.Rows = strings.Split(row.Data, "|")
		}
		if len(prefix) > 0 {
			row.Key = prefix[0] + row.Key
		}
	}
	return
}

// Find 查找满足指定条件的数据
func Find(parent string) (rows []*AppConf, err error) {
	if confdb == nil {
		err = errors.New("database is not set for config")
		return
	}
	if parent != "" {
		rs := confdb.Where("parent = ?", parent).Find(&rows)
		if rs.Error != nil {
			err = rs.Error
			return
		}
	} else {
		rs := confdb.Find(&rows)
		if rs.Error != nil {
			err = rs.Error
			return
		}
	}
	return
}

// Count 统计记录数
func Count(parent string) (n int64, err error) {
	if confdb == nil {
		err = errors.New("database is not set for config")
		return
	}
	err = confdb.Model(&AppConf{}).Where("parent=?", parent).Count(&n).Error
	return
}

// ClearTable 清空表
func ClearTable(parent string) error {
	return confdb.Where("parent=?", parent).Delete(&AppConf{}).Error
}

// AddRow 新加一行
// name 显示名称
// key 关键字
// value 值
// desc 描述
// scope 作用域
// type 类型
// data 类型值
func AddRow(name, key, value, desc, scope, typ, data string) *AppConf {
	if key == "" {
		return nil
	}
	if name == "" {
		return nil
	}
	row := new(AppConf)
	row.Name = name
	row.Key = key
	row.Value = value
	row.Desc = desc
	row.Scope = scope
	row.Type = typ
	row.Data = data
	return row
}

// Sync 同步到数据库
func Sync(table []*AppConf, parent string) (err error) {
	//1. 清空服务下的全部数据
	tx := confdb.Begin()
	if parent == "" {
		err = confdb.Delete(&AppConf{}).Error
	} else {
		err = confdb.Where("parent=?", parent).Delete(&AppConf{}).Error
	}
	if err != nil {
		tx.Rollback()
		return
	}

	//2. 插入新的数据
	for _, row := range table {
		row.Parent = parent
		err = tx.Create(row).Error
		if err != nil {
			logs.Warn(err)
		}
	}
	tx.Commit()
	return
}

// AddDefaultSerial 添加默认的串口配置
func AddDefaultSerial() []*AppConf {
	rows := make([]*AppConf, 0, 5)
	row := AddRow("串口地址", "serial", "COM1", "串口地址", "addServer", "", "")
	rows = append(rows, row)
	row = AddRow("波特率", "serial_baudrate", "9600", "波特率", "addServer", "select", "9600|4800|2400|14400|115200")
	rows = append(rows, row)
	row = AddRow("校验位", "serial_checkbit", "NONE", "校验位", "addServer", "select", "NONE|EVEN|ODD")
	rows = append(rows, row)
	row = AddRow("数据位", "serial_databit", "8", "数据位", "addServer", "select", "8|7")
	rows = append(rows, row)
	row = AddRow("停止位", "serial_stopbit", "1", "停止位", "addServer", "select", "1|2")
	rows = append(rows, row)
	return rows
}
